# Написать программу управления человечком на консоли:
#  0
# -+-
# / \
# Изначально человечек стоит по центру консоли.
# Если нажата одна из пяти клавиш управления, он начинает двигаться в соответствующую сторону или останавливается
# Вариант управления (можно другой):
#            8
#            ↑
#        4 ← 5 → 6
#            ↓
#            2
# Движение происходит согласно таймерному прерыванию (используется и консоль, и Timer Tool)
#  Таймер медленный — не чаще 5 раз в секунду 
# Ввод происходит по прерыванию от клавиатуры консоли
# На границе экрана человечек останавливается (или появляется с другой стороны — как вам удобнее)
# Допустимо в качестве «движения» сначала заполнять человечка пробелами, а затем выводить нового в новом месте
# <!> (бонус) можно предусмотреть затирание только того места, откуда человечек ушёл — тогда экран не будет моргать

.eqv		DISPLAYW	115
.eqv		DISPLAYH	10

.data
yes_t:		.word 0
run_char:	.word 0
run:		.word 0
check_disp:	.word 0
delta:		.word 0				# Изменение на 1 по координатам
man:		.word 0x3900507			# Расположение головы
		.word 0x30			# Голова - '0'
		.word 0x3800607			# Расположение левой руки
		.word 0x2d			# Левая рука - '-'
		.word 0x3900607			# Расвположение туловища
		.word 0x2b			# Туловище - '+'
		.word 0x3a00607			# Расположение правой руки
		.word 0x2d			# Правая рука - '-'
		.word 0x3800707			# Расположение левой ноги
		.word 0x2f			# Левая нога - '/'
		.word 0x3a00707			# Расположение правой ноги
		.word 0x5c			# Правая нога - '\'
	
.text
.globl main
main:
	lw      t0 0xffff0018		# Настроим прерывание
        addi    t0 t0 1
        sw      t0 0xffff0020 t1
        la      t0 handler
        csrw    t0 utvec
        csrsi   uie 0x110
        csrsi   ustatus 1
	
	li      t0 1
        sb      t0 0xffff0008 t1
	li      t0 2		        # Включеем прерывание от клавиатуры
	sw      t0 0xffff0000 t1
	
	jal	draw_man

loop:	lw	t0 run_char		# вечный цикл
	sw	zero run_char t1
	beqz	t0 check_run
	li      t1 0x1b		
	beq     t0 t1 exit              # ESC — конец
	li	t1 0x35
	beq	t0 t1 stop		# 5 - остановка
	li	t1 0x32
	beq	t0 t1 down		# 2 - вниз
	li	t1 0x34
	beq	t0 t1 left		# 4 - влево
	li	t1 0x38
	beq	t0 t1 up		# 8 - вверх
	li	t1 0x36
	beq	t0 t1 right		# 6 - вправо
	b	check_run
	
stop:	sw	zero run t1
	sw	zero delta t1
	b	check_run
down:	li	t0 1
	sw	t0 run t1
	li	t0 0x100
	sw	t0 delta t1
	b	check_run
up:	li	t0 1
	sw	t0 run t1
	li	t0 -0x100
	sw	t0 delta t1
	b	check_run
left:	li	t0 1
	sw	t0 run t1
	li	t0 -0x100000
	sw	t0 delta t1
	b	check_run
right:	li	t0 1
	sw	t0 run t1
	li	t0 0x100000
	sw	t0 delta t1
	
check_run:	
	lw	t0 check_disp
	beqz	t0 notdown
	la	t1 man			# Проверим выход за границы экрана
	lw	t0 16(t1) 
	srli	t1 t0 8			# Получим Y центра
	li	t2 0xfff		
	and	t1 t1 t2
	srli	t0 t0 20		# Получим X центра
	li	t2 1			# Выход за левую границу
	bgt	t0 t2 notleft
	sw	zero run t1
	sw	zero delta t1
	sw	zero check_disp t1
	b	loop
notleft:
	li	t2 DISPLAYW		# Выход за правую границу
	blt	t0 t2 notright
	sw	zero run t1
	sw	zero delta t1
	sw	zero check_disp t1
	b	loop
notright:
	li	t2 1			# Выход за верхнюю границу
	bgt	t1 t2 notup
	sw	zero run t1
	sw	zero delta t1
	sw	zero check_disp t1
	b	loop	
notup:
	li	t2 DISPLAYH		# Выход за нижнюю границу
	blt	t1 t2 notdown
	sw	zero run t1
	sw	zero delta t1
	sw	zero check_disp t1
	b	loop		
notdown:
	lw	t0 run
	beqz	t0 loop
loop_t:	lw	t0 yes_t
	beqz	t0 loop_t
	sw	zero yes_t t1	
	jal	draw_man
	li	t0 1
	sw	t0 check_disp t1
	b	loop

exit:	li      a7 10
        ecall
	

draw_man:
	addi    sp sp -16
        sw      ra (sp)
        sw	s1 4(sp)
        sw	s2 8(sp)
        sw	s11 12(sp)
	
	li	s11 6
	la	s2 man
	lw	t2 delta
dm_loop_space:				# Сперва затрем старые символы
	beqz	s11 dm_exit_space
	lw	s1 (s2)
dm_loopсur_space:			
	lb      t0 0xffff0008           # готовность вывода
        andi    t0 t0 1                 # есть?
        beqz    t0 dm_loopсur_space     # а надо! идём обратно
        sw      s1 0xffff000c t1        # запишем слово
        li	s1 0x20
dm_loopchar_space:       
        lb      t0 0xffff0008           # готовность вывода
        andi    t0 t0 1                 # есть?
        beqz    t0 dm_loopchar_space    # а надо! идём обратно
        sw      s1 0xffff000c t1        # запишем байт
	addi	s2 s2 8
	addi	s11 s11 -1
	b	dm_loop_space
	
dm_exit_space:				# Теперь выведем новые
	li	s11 6
	la	s2 man
dm_loop:
	beqz	s11 dm_exit		# Пошел вывод
	lw	s1 (s2)
	add	s1 s1 t2		# Изменим координаты
	sw	s1 (s2)			
dm_loopсur:					
	lb      t0 0xffff0008           # готовность вывода
        andi    t0 t0 1                 # есть?
        beqz    t0 dm_loopсur	        # а надо! идём обратно
        sw      s1 0xffff000c t1        # запишем слово
        addi	s2 s2 4
        lw	s1 (s2)
dm_loopchar:       
        lb      t0 0xffff0008           # готовность вывода
        andi    t0 t0 1                 # есть?
        beqz    t0 dm_loopchar	        # а надо! идём обратно
        sw      s1 0xffff000c t1        # запишем байт
        addi	s2 s2 4
	addi	s11 s11 -1
	b	dm_loop
	
dm_exit:
	lw	s11 12(sp)
	lw	s2 8(sp)
	lw	s1 4(sp)
	lw      ra, (sp)
        addi    sp, sp, 16
	ret


.data
h_t1:   .word   0

.text	
handler:
	csrw	t0 uscratch
	sw      t1 h_t1 t0          	# сохраним t1
        csrr    t0 ucause           	# рассмотрим тип прерывания
        andi    t0 t0 0x8         	# не будем проверять на исключение
        bnez    t0 h_in             	# считаем, что готовность ввода иначе таймер
h_time: li	t0 1			# Установим признак срабатывания таймера
	sb	t0 yes_t t1
	lw      t0 0xffff0018		# Добавим время для следующего прерывания
        addi    t0 t0 50
        sw      t0 0xffff0020 t1
	b	h_exit
h_in:   lw      t0 0xffff0004      	# готовность есть (по прерыванию)
        sw	t0 run_char t1		# запишем символ в буфер управления
h_exit: lw      t1 h_t1             	# вспоминаем t1
        csrr    t0 uscratch         	# вспоминаем t0
        uret
   
   
